package {

   import flash.display.Sprite;
   import flash.display.StageAlign;
   import flash.display.StageScaleMode;
   import flash.events.*;
   import flash.net.*;
   import flash.text.TextField;
   
   import fm.last.*;
   import fm.last.api.*;
   import fm.last.error.*;


   public class Example3 extends Sprite {

        /** LastFmService */
        private static var lfmServ:LastFmService = new LastFmService(BaseTC._api_key);
      
        /** get top 5 popular tags */
        private static const TAG_COUNT:int = 5;
        
        /** get top 4 popular artists from each given tag */
        private static const ARTIST_COUNT:int = 4;
        
        // for message layout 
        private static var layout_y:int = 5;
         
        public function Example3() 
        {        
            // setup stage
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            
            // show some message
            showMessage("Getting top artists from top tags...");
                        
            // begin with getting top tags
            loadTopTags();                                      
        }
        
        private function showMessage(str:String):void
        {
            var t:TextField = new TextField();
            t.text = str;
            t.x = 5;
            t.y = layout_y;
            t.width = 800; 
            t.wordWrap = true;            
            addChild(t);
            layout_y += 30;
        }
        
        /** load top tags */
        private function loadTopTags():void
        {
            lfmServ.tag.getTopTags(onGetTopTags, onError);    
        }  
        
        /** callback function, which is called when error occurs */
        private static function onError(e:ErrorEvent):void
        {
            throw e;
        }
        
        /** callback function, which is called when getting top tags */
        private function onGetTopTags(lfm:XML):void
        {
            /* // a successful response may be ....
             * <toptags>
             *  <tag>
             *    <name>rock</name>
             *    <count>1994155</count>
             *    <url>www.last.fm/tag/rock</url>
             *  </tag>
             *  ...
             * </toptags>
             */
            
            /* store result tags' name in array */
            var ta:Array = []; 
            for (var i:int=0; i < TAG_COUNT; i++) {
                ta.push(lfm.toptags.tag[i].name);
            }
                   
            // show some message
            showMessage("Top tags: " + ta.toString());
                   
            /* load top artists from those top tags */
            loadTopArtists(ta);                       
        }
        
        /** 
        * load top artist from given top tags.
        * 
        * We will retrive each tag's top artists one by one,
        * and combine all results together.
        *  
        * @param tags given tags Array<lfm.toptags.tag[].name> 
        */
        public function loadTopArtists(tags:Array):void
        {               
            /* 
             * result artists array  
             */
            var aa:Array = [];  
            /* *****************************************************************/
                             
            /* 
             * This is a function which can generate a chained (callback) function. 
             * A chained (callback) functions is to retrive top artists of each tag,
             * and to invoke another chained function.   
             */     
            var genChainedFunction:Function = function(nextChainedFunc:Function,                                                    
                                                    nextTag:String):Function {
                                                                         
                return function(lfm:XML):void {    
                        
                        /* load artists result of a tag */
                        var at:Array = [];                                                                                    
                        for (var i:int=0; i < ARTIST_COUNT; i++) {
                            /* successful response is... 
                             * <topartists tag="Disco">
                             *    <artist rank="">
                             *      <name>ABBA</name>
                             *      ...
                             *    </artist>
                             * ...
                             * </topartists>
                             */
                            at.push(lfm.topartists.artist[i].name);
                        }                                               
                        // show some message
                        showMessage("Tag ["+ lfm.topartists.@tag + "]: " + at);
                        
                        // collect them to the result
                        aa = aa.concat(at);
                        
                        if (nextChainedFunc==null) {
                            /* the end of chain! 
                             * we have collected all results and can further process them.
                             */                                
                            onGetTopArtists(aa);
                        } else {
                            /* find top artists for next tag
                             * and invoke next chained function: 
                             */
                            lfmServ.tag.getTopArtists(nextChainedFunc, onError, nextTag);
                        } 
                    };   
                };
            /* *****************************************************************/
            
            /*
             * create an array of chained functions.
             * The nuumber of chained functions is equal to the number of top tags.
             */    
            var chain:Array = []; 
            
            // chain[tags.length-1] is the function on the end of chain
            chain[tags.length-1] = genChainedFunction(null, null);
            for (var i:int=tags.length-2; i>=0; i--) {                
                chain[i] = genChainedFunction(chain[i+1], tags[i+1]);    
            }                                           
            /* *****************************************************************/
                                            
            /* begin calling chained functions from the first one */ 
            lfmServ.tag.getTopArtists(chain[0], onError, tags[0]);            
        }
        
        /** callback function which is called whem getting top artists */
        private function onGetTopArtists(topArtists:Array):void
        {           
            var artistNames:Array = [];
            for each(var name:String in topArtists) {
                artistNames.push(name);
            }
            
            // filter out duplicated artists
            artistNames = artistNames.filter(
                            function(e:*, i:int, a:Array):Boolean {
                                return (a.indexOf(e,i+1)==-1);
                            });
                            
            var traceStr:String = "Total " + artistNames.length + " artists:\n" + artistNames.toString();            
            
            trace(traceStr);
            
            // show some message
            showMessage(traceStr);                        
                                                            
        }
        

       
   }
}